package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.heima.api.feign.IScheduleFeginClient;
import com.heima.common.exception.CustomException;
import com.heima.model.common.constants.WmNewsMessageConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.enums.TaskTypeEnum;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.common.ProtostuffUtil;
import com.heima.utils.threadlocal.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

	@Autowired
	private WmNewsMaterialMapper wmNewsMaterialMapper;

	@Autowired
	private WmMaterialMapper wmMaterialMapper;

	@Autowired
	private RabbitTemplate rabbitTemplate;

	@Autowired
	private WmNewsTaskService wmNewsTaskService;

	@Autowired
	private IScheduleFeginClient scheduleClient;

	@Autowired
	private WmAutoScanService wmAutoScanService;


	/**
	 * 查询文章列表
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult list(WmNewsPageReqDto dto) {
		// 1.非空判断
		dto.checkParam();
		// 2.分页查询
		IPage<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
		LambdaQueryWrapper<WmNews> queryWrapper = Wrappers.lambdaQuery();
		// 2.1 根据状态查询
		if (dto.getStatus() != null) {
			queryWrapper.eq(WmNews::getStatus, dto.getStatus());
		}

		// 2.2 根据关键字查询
		if (!StringUtils.isEmpty(dto.getKeyword())) {
			queryWrapper.like(WmNews::getTitle, dto.getKeyword());
		}

		// 2.3 根据频道id查询
		if (dto.getChannelId() != null) {
			queryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
		}

		// 2.4 根据开始和结束时间查询
		if (dto.getBeginPubdate() != null && dto.getEndPubdate() != null) {
			queryWrapper.between(WmNews::getPublishTime, dto.getBeginPubdate(), dto.getEndPubdate());
		}

		// 2.5 根据登录用户id查询
		queryWrapper.eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId());
		queryWrapper.orderByDesc(WmNews::getCreatedTime);

		page = super.page(page, queryWrapper);

		// 3.返回数据结果
		ResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
		result.setData(page.getRecords());
		return result;
	}

	/**
	 * 保存-修改-提交草稿为一体的方法
	 * 主方法
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult submit(WmNewsDto dto) {
		// 0. 参数校验
		if (dto == null || dto.getContent() == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}

		// 1. 保存或修改文章
		WmNews wmNews = new WmNews();
		BeanUtils.copyProperties(dto, wmNews);
		// 1.1 封面
		if (dto.getImages() != null && dto.getImages().size() > 0) {
			String imageStr = StringUtils.join(dto.getImages(), ",");
			wmNews.setImages(imageStr);
		}
		// 1.2 如果封面为自动-1,则需要手动设置封面规则
		if (dto.getType().equals((short)-1)) {
			wmNews.setType(null);
		}
		saveorUpdateWmNews(wmNews);

		// 2. 判断是否为草稿,如果为草稿结束当前方法
		if (wmNews.getStatus().equals(WmNews.Status.NORMAL.getCode())) {
			return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
		}

		// 3. 不是草稿保存文章内容与图片素材之间关系
		// 3.1 获取文章的图片素材
		List<String> imageList = extractUrlInfo(dto.getContent());
		saveRelativeInfoForContent(imageList, wmNews.getId());

		// 4. 不是草稿,保存文章封面图片与图片素材的关系
		saveRelativeInfoForCover(dto, wmNews, imageList);

		//5. 审核文章
		wmAutoScanService.autoScanWmNews(wmNews.getId());
		//将文章id和发布时间添加到任务中
		wmNewsTaskService.addNewsToTask(wmNews.getId(),dto.getPublishTime());

		// 6.返回数据
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}

	/**
	 * 保存文章封面图片与图片素材的关系
	 * 如果当前为自动，进行匹配：
	 * 1、若当前图片大于等于1，小于三张，设置为单图 type=1
	 * 2、若当前图片大于等于三张，设置为多图 type=3
	 * 3、若当前没有图片，设置为无图 type=0
	 *
	 * @param dto
	 * @param wmNews
	 * @param imageList
	 */
	private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> imageList) {
		List<String> images = dto.getImages();

		// 处理封面为自动的情况
		if (dto.getType().equals((short)-1)) {
			// 单图
			if (dto.getType() >= 1 && imageList.size() < 3) {
				wmNews.setType((short) 1);
				images = imageList.stream().limit(1).collect(Collectors.toList());
			} else if (imageList.size() > 3) {
				// 多图
				wmNews.setType((short) 3);
				images = imageList.stream().limit(3).collect(Collectors.toList());
			} else {
				// 无图
				wmNews.setType((short) 0);
			}

			// 修改文章
			if (images != null && images.size() > 0) {
				wmNews.setImages(StringUtils.join(images, ","));
			}
			updateById(wmNews);
		}
		// 保存封面与图片素材的关系
		if (images != null && images.size() > 0){
			saveRelativeInfo(images,wmNews.getId(), (short) 1);
		}
	}


	/**
	 * 保存文章封面图片与图片素材的关系
	 *
	 * @param imageList
	 * @param id
	 */
	private void saveRelativeInfoForContent(List<String> imageList, Integer id) {
		saveRelativeInfo(imageList, id, (short) 1);
	}

	/**
	 * 保存文章图片与素材的关系到数据库
	 *
	 * @param imageList
	 * @param id
	 * @param i
	 */
	private void saveRelativeInfo(List<String> imageList, Integer id, Short i) {
		if (imageList != null && !imageList.isEmpty()) {
			// 通过图片URL查询素材Id
			List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, imageList));
			// 判断素材是否有用
			if (dbMaterials == null || dbMaterials.size() == 0) {
				// 手动抛异常
				throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
			}
			if (dbMaterials.size() != imageList.size()) {
				throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
			}
			List<Integer> dbMaterialsIds = dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
			wmNewsMaterialMapper.saveRelations(dbMaterialsIds, id, i);
		}
	}

	/**
	 * 提取文章内容中的图片信息
	 *
	 * @param content
	 * @return
	 */
	private List<String> extractUrlInfo(String content) {
		List<String> materials = new ArrayList<>();
		List<Map> maps = JSON.parseArray(content, Map.class);
		for (Map map : maps) {
			if (map.get("type").equals("image")) {
				String imgUrl = (String) map.get("value");
				materials.add(imgUrl);
			}
		}
		return materials;
	}

	/**
	 * 保存或修改文章
	 *
	 * @param wmNews
	 */
	private void saveorUpdateWmNews(WmNews wmNews) {
		// 不全属性
		wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
		wmNews.setCreatedTime(new Date());
		wmNews.setSubmitedTime(new Date());
		// 默认上架
		wmNews.setEnable((short) 1);
		if (wmNews.getId() == null) {
			// 如果没有就是新增
			save(wmNews);
		} else {
			// 修改
			// 删除文章和素材的关系
			wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
			// 更新文章
			updateById(wmNews);
		}
	}

	/**
	 * 文章上下架
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult downOrUp(WmNewsDto dto) {
		// 根据Id查询文章
		WmNews wmNews = this.lambdaQuery().eq(WmNews::getId, dto.getId()).one();
		if (wmNews.getArticleId() ==null){
			return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST,"文章不存在");
		}
		if (wmNews.getStatus() != 9){
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"当前文章不是发布状态");
		}
		wmNews.setEnable(dto.getEnable());

		updateById(wmNews);
		ObjectMapper objectMapper = new ObjectMapper();
		Map<String,Object> map = new HashMap<>();
		map.put("articleId",wmNews.getArticleId());
		map.put("enable",wmNews.getEnable());
		try {
			rabbitTemplate.convertAndSend(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_ROUTINGKEY, objectMapper.writeValueAsString(map));
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		return ResponseResult.okResult("文章上下架完成");
	}

	@Autowired
	private WmAutoScanService wmNewAutoScanService;


	/**
	 * 消费任务，审核文章
	 */
	@Async
	@Scheduled(fixedRate = 100000)
	public void scanNewsByTask() {
		log.info("开始执行文章自动审核任务");
		ResponseResult responseResult = scheduleClient.poll(TaskTypeEnum.NEWS_SCAN_TIME.getTaskType(), TaskTypeEnum.NEWS_SCAN_TIME.getPriority());
		if(responseResult.getCode().equals(200)&&responseResult.getData()!=null){
			log.info("task:{}",responseResult.getData());
			String jsonTask = JSON.toJSONString(responseResult.getData());
			Task task = JSON.parseObject(jsonTask, Task.class);
			//逆序列化任务参数拿到id
			WmNews wmNews = ProtostuffUtil.deserialize(task.getParameters(), WmNews.class);
			wmNewAutoScanService.autoScanWmNews(wmNews.getId());
		}
	}

	/**
	 * 根据文章Id查询
	 *
	 * @param id
	 * @return
	 */
	@Override
	public WmNews getByArticalId(Long id) {
		WmNews wmNews = this.getOne(Wrappers.<WmNews>lambdaQuery().eq(WmNews::getArticleId, id));
		return wmNews;
	}
}
